// WMS Library - http://wmslib.codeplex.com/
// Copyright (c) Tom Gaskins 2004 - Erik Putrycz 2013
// Licensed under the Microsoft Public License (Ms-PL)

using System.Xml.Linq;
using System.Linq;
using System.IO;
using System.Collections.Generic;

namespace WMSLib.Client
{
	///
	/// Class for determining WMS server capabilities. Contains accessors to
	/// fields in the capabilities description returned as an XML document
	/// from a WMS server.
	///
	public class Capabilities
	{
		private XDocument doc; // The root of the XML document.
		private Server server; // The Wms.Client.Server object associated with these capabilities.
		private XElement _service;
		private XElement _capability;
		private List<Layer> _layers;

		public Capabilities(Server server)
		{
			this.server = server;
		}

		public void LoadData(Stream stream)
		{
			// Constructor requires a path to an XML capabilities file,
			// and a reference to a Wms.Client.Server object.
			this.doc = XDocument.Load(stream);
			_service = doc.Descendants("Service").FirstOrDefault();
			_capability = doc.Descendants("Capability").FirstOrDefault();
		}

		// The next several "Get" functions are utilities for parsing the capabilities
		// document.

		static public string ExpandPattern(string pattern)
		{
			// The 'Url' vs. 'URL' case is so prevalent that we account for it here rather
			// than in all the invoking instances.
			if ((!pattern.Equals(string.Empty)) && (pattern.IndexOf("Url") >= 0))
			{
				pattern = pattern + "|" + pattern.Replace("Url", "URL");
			}
			return pattern = pattern + "|" + pattern.ToLower() + "|" + pattern.ToUpper();
		}



		// These following functions use an XPath string to identify the elements of
		// the XML capabilities to find and return.

		public string ServiceOnlineResource
		{
			get { return _service.Descendants("OnlineResource").First().Value; }
		}

		public string Version
		{
			get { return doc.Root.Attribute("version").Value; }
		}

		public string UpdateSequence
		{
			get { return doc.Root.Attribute("updateSequence").Value; }
		}

		public string ServiceName
		{
			get { return _service.Descendants("Name").First().Value; }
		}

		public string ServiceTitle
		{
			get { return _service.Descendants("Title").First().Value; }
		}

		public string ServiceAbstract
		{
			get { return _service.Descendants("Abstract").First().Value; }
		}

		public List<string> ServiceKeywordList
		{
			get { return _service.Descendants("KeywordList").First().Descendants("Keyword").Select(t => t.Value).ToList(); }
		}

		public string ServiceFees
		{
			get { return _service.Descendants("Fees").First().Value; }
		}

		//public string ServiceAccessConstraints
		//{
		//    get {return GetStringInstance(this.doc, @"/*/Service/AccessConstraints");}
		//}

		//public string ServiceContactPerson
		//{
		//    get {return GetStringInstance(this.doc, @"/*/Service/ContactInformation/ContactPersonPrimary/ContactPerson");}
		//}

		//public string ServiceContactOrganization
		//{
		//    get {return GetStringInstance(this.doc, @"/*/Service/ContactInformation/ContactPersonPrimary/ContactOrganization");}
		//}

		//public string ServiceContactPosition
		//{
		//    get {return GetStringInstance(this.doc, @"/*/Service/ContactInformation/ContactPosition");}
		//}

		//public string ServiceContactVoiceTelephone
		//{
		//    get {return GetStringInstance(this.doc, @"/*/Service/ContactInformation/ContactVoiceTelephone");}
		//}

		//public string ServiceContactFacsimileTelephone
		//{
		//    get {return GetStringInstance(this.doc, @"/*/Service/ContactInformation/ContactFacsimileTelephone");}
		//}

		//public string ServiceContactElectronicMailAddress
		//{
		//    get {return GetStringInstance(this.doc, @"/*/Service/ContactInformation/ContactElectronicMailAddress");}
		//}

		//public string ServiceContactAddressType
		//{
		//    get {return GetStringInstance(this.doc, @"/*/Service/ContactInformation/ContactAddress/AddressType");}
		//}

		//public string ServiceContactAddress
		//{
		//    get {return GetStringInstance(this.doc, @"/*/Service/ContactInformation/ContactAddress/Address");}
		//}

		//public string ServiceContactAddressCity
		//{
		//    get {return GetStringInstance(this.doc, @"/*/Service/ContactInformation/ContactAddress/City");}
		//}

		//public string ServiceContactAddressStateOrProvince
		//{
		//    get {return GetStringInstance(this.doc, @"/*/Service/ContactInformation/ContactAddress/StateOrProvince");}
		//}

		//public string ServiceContactAddressPostCode
		//{
		//    get {return GetStringInstance(this.doc, @"/*/Service/ContactInformation/ContactAddress/PostCode");}
		//}

		//public string ServiceContactAddressCountry
		//{
		//    get {return GetStringInstance(this.doc, @"/*/Service/ContactInformation/ContactAddress/Country");}
		//}

		//public string GetCapabilitiesRequestUri
		//{
		//    get {return GetOnlineResourceInstance(this.doc, @"/*/Capability/Request/GetCapabilities/DCPType/HTTP/Get/OnlineResource");}
		//}

		//public string GetMapRequestUri
		//{
		//    get {return GetOnlineResourceInstance(this.doc, @"/*/Capability/Request/GetMap/DCPType/HTTP/Get/OnlineResource");}
		//}

		//public string GetFeatureInfoRequestUri
		//{
		//    get {return GetOnlineResourceInstance(this.doc, @"/*/Capability/Request/GetFeatureInfo/DCPType/HTTP/Get/OnlineResource");}
		//}

		//public string DescribeLayerRequestUri
		//{
		//    get {return GetOnlineResourceInstance(this.doc, @"/*/Capability/Request/DescribeLayer/DCPType/HTTP/Get/OnlineResource");}
		//}

		//public string GetLegendGraphicRequestUri
		//{
		//    get {return GetOnlineResourceInstance(this.doc, @"/*/Capability/Request/GetLegendGraphic/DCPType/HTTP/Get/OnlineResource");}
		//}

		//public string GetStylesRequestUri
		//{
		//    get {return GetOnlineResourceInstance(this.doc, @"/*/Capability/Request/GetStyles/DCPType/HTTP/Get/OnlineResource");}
		//}

		//public string PutStylesRequestUri
		//{
		//    get {return GetOnlineResourceInstance(this.doc, @"/*/Capability/Request/PutStyles/DCPType/HTTP/Get/OnlineResource");}
		//}

		//public string[] GetCapabilitiesRequestFormats
		//{
		//    get {return GetStringsInstance(this.doc, @"/*/Capability/Request/GetCapabilities/Format");}
		//}

		//public string[] GetMapRequestFormats
		//{
		//    get {return GetStringsInstance(this.doc, @"/*/Capability/Request/GetMap/Format");}
		//}

		//public string[] GetFeatureInfoRequestFormats
		//{
		//    get {return GetStringsInstance(this.doc, @"/*/Capability/Request/GetFeatureInfo/Format");}
		//}

		//public string[] DescribeLayerRequestFormats
		//{
		//    get {return GetStringsInstance(this.doc, @"/*/Capability/Request/DescribeLayer/Format");}
		//}

		//public string[] GetLegendGraphicRequestFormats
		//{
		//    get {return GetStringsInstance(this.doc, @"/*/Capability/Request/GetLegendGraphic/Format");}
		//}

		//public string[] GetStylesRequestFormats
		//{
		//    get {return GetStringsInstance(this.doc, @"/*/Capability/Request/GetStyles/Format");}
		//}

		//public string[] PutStylesRequestFormats
		//{
		//    get {return GetStringsInstance(this.doc, @"/*/Capability/Request/PutStyles/Format");}
		//}

		//public string[] ExceptionFormats
		//{
		//    get {return GetStringsInstance(this.doc, @"/*/Capability/Exception/Format");}
		//}

		public List<Layer> Layers
		{
			get
			{
				if (_layers != null)
					return _layers;
				_layers = _capability.Descendants("Layer").Select(el => new Layer(el, server)).ToList();
				return _layers;
			}
		}

		public class UserDefinedSymbolizationType
		{
			public bool SupportSld;
			public bool UserLayer;
			public bool UserStyle;
			public bool RemoteWfs;
		}

		//public UserDefinedSymbolizationType UserDefinedSymbolization
		//{
		//    get
		//    {
		//        System.Xml.XPath.XPathNodeIterator iter
		//            = this.doc.CreateNavigator().Select(ExpandPattern(@"./UserDefinedSymbolization"));
		//        UserDefinedSymbolizationType retVal = new UserDefinedSymbolizationType();
		//        if (iter.MoveNext())
		//        {
		//            retVal.SupportSld = GetBooleanInstance(iter.Current, @"./@SupportSld|./@SupportSLD");
		//            retVal.UserLayer = GetBooleanInstance(iter.Current, @"./@UserLayer");
		//            retVal.UserStyle = GetBooleanInstance(iter.Current, @"./@UserStyle");
		//            retVal.RemoteWfs = GetBooleanInstance(iter.Current, @"./@RemoteWfs|./@RemoteWFS");
		//        }
		//        return retVal;
		//    }
		//}
	}
}